/* Esptouch example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/gpio.h"
#include "esp_wifi.h"
#include "esp_eap_client.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#include "esp_mac.h"
#include "nvs_hashmap.h"
#include "led_pwm.h"
#include "approxy4esp.h"
#include "esp_MesSWITCH.h"
#include "esp_task_wdt.h"
#include "SwitchAPI.h"
#include "esp_timer.h"
// #include "Gr_Switch.h"
// #include "RCSwitch.h"
// #include "TCSwitch.h"

/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t s_wifi_event_group;
nvs_ssid_pass_t *wifi_ssid_pass = NULL;
/* The event group allows multiple bits for each event,
   but we only care about one event - are we connected
   to the AP with an IP? */
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "esp_main";

static void smartconfig_example_task(void * parm);
static void esp_main_task(void * parm);

void initialise_approxy(void *arg);


int s_retry_num = 0;
int MAX_RETRY_NUM  = 10;


#define TWDT_TIMEOUT_MS         6000
#define TASK_RESET_PERIOD_MS    2000
#define MAIN_DELAY_MS           10000

// 创建事件句柄
ESP_EVENT_DEFINE_BASE(WATCHDOG_EVENT);
enum {
    WATCHDOG_EVENT_TIMEOUT,
};

static volatile bool run_loop;
static esp_task_wdt_user_handle_t func_a_twdt_user_hdl;
static esp_task_wdt_user_handle_t func_b_twdt_user_hdl;

static void func_a(void)
{
    esp_task_wdt_reset_user(func_a_twdt_user_hdl);
}

static void func_b(void)
{
    esp_task_wdt_reset_user(func_b_twdt_user_hdl);
}

void task_func(void *arg)
{
    // Subscribe this task to TWDT, then check if it is subscribed
    ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
    ESP_ERROR_CHECK(esp_task_wdt_status(NULL));

    // Subscribe func_a and func_b as users of the the TWDT
    ESP_ERROR_CHECK(esp_task_wdt_add_user("func_a", &func_a_twdt_user_hdl));
    ESP_ERROR_CHECK(esp_task_wdt_add_user("func_b", &func_b_twdt_user_hdl));

    printf("Subscribed to TWDT\n");

    while (run_loop) {
        // Reset the task and each user periodically
        /*
        Note: Comment out any one of the calls below to trigger the TWDT
        */
        esp_task_wdt_reset();
        func_a();
        func_b();

        vTaskDelay(pdMS_TO_TICKS(TASK_RESET_PERIOD_MS));
    }

    // Unsubscribe this task, func_a, and func_b
    ESP_ERROR_CHECK(esp_task_wdt_delete_user(func_a_twdt_user_hdl));
    ESP_ERROR_CHECK(esp_task_wdt_delete_user(func_b_twdt_user_hdl));
    ESP_ERROR_CHECK(esp_task_wdt_delete(NULL));

    printf("Unsubscribed from TWDT\n");

    // Notify main task of deletion
    xTaskNotifyGive((TaskHandle_t)arg);
    vTaskDelete(NULL);
}


static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
   
    if(event_base == HMap_EVENT && event_id == HM_EVENT_SSID_PASSWORD){
        wifi_config_t wifi_config;
        nvs_ssid_pass_t *spw = (nvs_ssid_pass_t *)event_data;
        ESP_LOGI(TAG, "读取取到ssid.. 开始连接wifi..");

        bzero(&wifi_config, sizeof(wifi_config_t));
        memcpy(wifi_config.sta.ssid, spw->ssid, sizeof(wifi_config.sta.ssid));
        memcpy(wifi_config.sta.password, spw->pass, sizeof(wifi_config.sta.password));

        //ESP_ERROR_CHECK( esp_wifi_disconnect() );
        ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
        esp_wifi_connect();
        s_retry_num = 0;
        //free(spw);
        
    } else if (event_base == HMap_EVENT && event_id == HM_EVENT_SSID_PASSWORD_NULL) {
        ESP_LOGI(TAG, "smartconfig_example_task...");
        xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
    } else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED){
        ESP_LOGI(TAG, "WiFi 已连接");
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        wifi_event_sta_disconnected_t* discon = (wifi_event_sta_disconnected_t*)event_data;
        ESP_LOGE(TAG, "WiFi 连接断开，SSID: %s, 原因: %d",   (char*)discon->ssid, discon->reason);
        
        // 尝试重连
        if (s_retry_num < MAX_RETRY_NUM) {
            esp_wifi_connect();
            xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
            s_retry_num++;
            ESP_LOGI(TAG, "尝试重连 (%d/%d)", s_retry_num, MAX_RETRY_NUM);
        } else {
            ESP_LOGE(TAG, "达到最大重连次数，停止尝试");
            // 可以在这里实现更复杂的逻辑，如重启系统
            esp_restart();
        }
        //esp_wifi_connect();
        //xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        char ip_str[16];
        esp_ip4addr_ntoa(&event->ip_info.ip, ip_str, sizeof(ip_str));
        ESP_LOGI(TAG, "当前IP地址: %s", ip_str);
       wifi_event_sta_connected_t* connected = (wifi_event_sta_connected_t*)event_data;

        ESP_LOGI(TAG, "Connected to SSID: %02x:%02x:%02x:%02x:%02x:%02x",
            connected->ssid[0], connected->ssid[1], connected->ssid[2],
            connected->ssid[3], connected->ssid[4], connected->ssid[5]);

        ESP_LOGI(TAG, "Connected to BSSID: %02x:%02x:%02x:%02x:%02x:%02x",
            connected->bssid[0], connected->bssid[1], connected->bssid[2],
            connected->bssid[3], connected->bssid[4], connected->bssid[5]);


        //xTaskCreate(initialise_approxy, "approxy4esp_task", 2048,  NULL, 3, NULL);
        initialise_approxy(NULL);

    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
        ESP_LOGI(TAG, "Scan done");
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
        ESP_LOGI(TAG, "Found channel");
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
        ESP_LOGI(TAG, "Got SSID and password");

        smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
        wifi_config_t wifi_config;
        uint8_t ssid[33] = { 0 };
        uint8_t password[65] = { 0 };
        uint8_t rvd_data[33] = { 0 };
        esp_err_t err = 0;
        bzero(&wifi_config, sizeof(wifi_config_t));
        memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
        memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));

#ifdef CONFIG_SET_MAC_ADDRESS_OF_TARGET_AP
        wifi_config.sta.bssid_set = evt->bssid_set;
        if (wifi_config.sta.bssid_set == true) {
            ESP_LOGI(TAG, "Set MAC address of target AP: "MACSTR" ", MAC2STR(evt->bssid));
            memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
        }
#endif

        memcpy(ssid, evt->ssid, sizeof(evt->ssid));
        memcpy(password, evt->password, sizeof(evt->password));
        ESP_LOGI(TAG, "SSID:%s", ssid);
        ESP_LOGI(TAG, "PASSWORD:%s", password);

        err = nvs_hashmap_put_string("SSID",(char *)ssid);
        if (err != ESP_OK) {
            ESP_LOGE(TAG, "存储SSID失败");
        }
        err = nvs_hashmap_put_string("PASSWORD", (char *)password);
        if (err != ESP_OK) {
            ESP_LOGE(TAG, "存储PASSWORD失败");
        }

        if (evt->type == SC_TYPE_ESPTOUCH_V2) {
            ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
            ESP_LOGI(TAG, "RVD_DATA:");
            for (int i=0; i<33; i++) {
                printf("%02x ", rvd_data[i]);
            }
            printf("\n");
        }

        ESP_ERROR_CHECK( esp_wifi_disconnect() );
        ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
        esp_wifi_connect();
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
        ESP_LOGI(TAG, "WiFi SC_EVENT_SEND_ACK_DONE");
        xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
    } else if (event_base == WATCHDOG_EVENT && event_id == WATCHDOG_EVENT_TIMEOUT) {
        ESP_LOGE(TAG, "Watchdog timeout event received");
    }

}

void initialise_approxy(void *arg) {
    char *loginName  = "kim";
    char *password  = "123456";
    start_Approxy4Esp(loginName,strlen(loginName),password,strlen(password),1);

}

static void initialise_wifi(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    s_wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );

    ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(HMap_EVENT, HM_EVENT_SSID_PASSWORD, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(HMap_EVENT, HM_EVENT_SSID_PASSWORD_NULL, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(WATCHDOG_EVENT, WATCHDOG_EVENT_TIMEOUT, &event_handler, NULL) );

          
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}

static void smartconfig_example_task(void * parm)
{
    EventBits_t uxBits;
    ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
    smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
    while (1) {
        uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
        if(uxBits & CONNECTED_BIT) {
            ESP_LOGI(TAG, "WiFi Connected to ap");
        }
        if(uxBits & ESPTOUCH_DONE_BIT) {
            ESP_LOGI(TAG, "smartconfig over");
            esp_smartconfig_stop();
            vTaskDelete(NULL);
        }
    }
}

static void esp_main_task(void * parm)
{

    // 初始化LED PWM控制库，使用GPIO2和LEDC通道0
   //ESP_ERROR_CHECK(led_pwm_init(GPIO_NUM_2, LEDC_CHANNEL_0));
    ESP_LOGI(TAG, "Starting breathing effect...");

    while (1) {
        // led_pwm_start_breathing(3000);
        
        SwitchAvailable();
        vTaskDelay(pdMS_TO_TICKS(10));
    }

   // led_pwm_stop_effects();
    //led_pwm_deinit();
}


// 初始化指定GPIO为输出模式并置高电平
esp_err_t init_gpio_output(gpio_num_t gpio_num,int level) {
    // 配置GPIO参数
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << gpio_num),  // 指定引脚
        .mode = GPIO_MODE_OUTPUT,            // 输出模式
        .pull_up_en = GPIO_PULLUP_DISABLE,  // 禁用上拉
        .pull_down_en = GPIO_PULLDOWN_DISABLE, // 禁用下拉
        .intr_type = GPIO_INTR_DISABLE,     // 禁用中断
    };
    
    // 应用GPIO配置
    esp_err_t err = gpio_config(&io_conf);
    if (err != ESP_OK) {
        ESP_LOGE("GPIO", "Failed to configure GPIO: %s", esp_err_to_name(err));
        return err;
    }
    
    // 设置GPIO为高电平
    err = gpio_set_level(gpio_num, level);
    if (err != ESP_OK) {
        ESP_LOGE("GPIO", "Failed to set GPIO high: %s", esp_err_to_name(err));
        return err;
    }
    
    ESP_LOGI("GPIO", "GPIO %d initialized as output and set to high", gpio_num);
    return ESP_OK;
}
 int64_t last_time = 0;
// 中断服务函数 (ISR)
void IRAM_ATTR gpio_isr_handler(void* arg) {
    uint32_t gpio_num = (uint32_t) arg;
    int64_t time = esp_timer_get_time();
    if(time - last_time > 10){
        ESP_EARLY_LOGI("GPIO", "GPIO[%d] 触发中断，电平: %d",  gpio_num, gpio_get_level(gpio_num));
        last_time = time;
    }
}
    

void app_main()
{

#if !CONFIG_ESP_TASK_WDT_INIT
    // If the TWDT was not initialized automatically on startup, manually intialize it now
    esp_task_wdt_config_t twdt_config = {
        .timeout_ms = TWDT_TIMEOUT_MS,
        .idle_core_mask = (1 << CONFIG_FREERTOS_NUMBER_OF_CORES) - 1,    // Bitmask of all cores
        .trigger_panic = false,
    };
    ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
    printf("TWDT initialized\n");
#endif // CONFIG_ESP_TASK_WDT_INIT


 // Create a task
    run_loop = true;
    xTaskCreatePinnedToCore(task_func, "task", 2048, xTaskGetCurrentTaskHandle(), 10, NULL, 0);

    // 检查重启原因
    esp_reset_reason_t reason = esp_reset_reason();
    ESP_LOGI(TAG, "Reset reason: %d", reason);

    // 初始化NVS HashMap
    esp_err_t err = nvs_hashmap_init();

    if (err != ESP_OK) {
        ESP_LOGE(TAG, "NVS HashMap初始化失败");
        return;
    }

    // 初始化wifi模块
    initialise_wifi();

    // 读取设备的MAC地址
    uint8_t mac[6];
    err = esp_read_mac(mac, ESP_MAC_WIFI_STA);
    if (err == ESP_OK) {
        ESP_LOGI(TAG, "设备的MAC地址: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    } else {
        ESP_LOGE(TAG, "读取MAC地址失败，错误代码: %d", err);
    }

    // 读取wifi密码
    char ssid[50] = {0};
    char pass[50] = {0};
    err = nvs_hashmap_get_string("SSID", ssid, sizeof(ssid));
    if (err == ESP_OK) {
        ESP_LOGI(TAG, "读取到SSID: %s", ssid);
    } else if (err == ESP_ERR_NVS_NOT_FOUND) {
        ESP_LOGI(TAG, "SSID键不存在");
    } else {
        ESP_LOGE(TAG, "读取SSID失败");
    }
    err = nvs_hashmap_get_string("PASSWORD", pass, sizeof(pass));
    if (err == ESP_OK) {
        ESP_LOGI(TAG, "读取到pass: %s", pass);
        if(strlen(ssid) > 0 && strlen(pass) > 0){
            // 手动触发事件
            nvs_ssid_pass_t *spw = malloc(sizeof(nvs_ssid_pass_t));
            bzero(spw->ssid,sizeof(spw->ssid));
            bzero(spw->pass,sizeof(spw->pass));
            memcpy(spw->ssid,ssid,strlen(ssid));
            memcpy(spw->pass,pass,strlen(pass));
            esp_event_post(HMap_EVENT, HM_EVENT_SSID_PASSWORD, spw, sizeof(nvs_ssid_pass_t), portMAX_DELAY);
            
        }
    } else if (err == ESP_ERR_NVS_NOT_FOUND) {
        ESP_LOGI(TAG, "PASSWORD键不存在");
        esp_event_post(HMap_EVENT, HM_EVENT_SSID_PASSWORD_NULL, NULL, 0, portMAX_DELAY);
    } else {
        ESP_LOGE(TAG, "读取PASSWORD失败");
    }

    ESP_LOGI(TAG,"可用堆内存：%dkb",esp_get_free_heap_size()/1024);
    MesSWITCH_init();


    int initial_level = gpio_get_level(GPIO_NUM_25);
    ESP_LOGI("APP", "Initial level of GPIO25: %d", initial_level);

    // 翻转GPIO2（假设连接了LED）
    gpio_set_direction(GPIO_NUM_2,GPIO_MODE_OUTPUT);

    // 安装GPIO ISR服务（必须先调用）
    gpio_install_isr_service(0);

    //gpio_isr_handler_add((gpio_num_t)(GPIO_NUM_25), (gpio_isr_t)gpio_isr_handler, (void*) (GPIO_NUM_25));
    if(1){
         SwitchBegin();
    }
    
   
    // esp_RF_init();
    //init_gpio_output(25,1);
    esp_main_task(NULL);
    //xTaskCreate(esp_main_task, "esp_main_task", 1024, NULL, 3, NULL);
}
